module ysyx_050369_Par_product (
    input  [2:0]    src,
    input  [65:0]   X,
    output          C,
    output [66:0]   P
);

wire y_add,y,y_sub;
wire sel_negative,sel_double_negative,sel_positive,sel_double_positive;
assign {y_add,y,y_sub} = src;

assign sel_negative =  y_add & (y & ~y_sub | ~y & y_sub);//=-x
assign sel_positive = ~y_add & (y & ~y_sub | ~y & y_sub);//= x
assign sel_double_negative =  y_add & ~y & ~y_sub;       //=2x
assign sel_double_positive = ~y_add &  y &  y_sub;       //=-2x
assign P =  sel_negative        ?{1'b0,~X}:(
            sel_positive        ?{1'b0, X}:(
            sel_double_negative ?{~X,1'b1}:(
            sel_double_positive ?{ X,1'b0}:'b0)));
assign C =  (sel_double_negative|sel_negative) ?  1'b1 : 1'b0;
endmodule
module ysyx_050369_walloc_n(
    input               clk,
    input               rst,
    input               valid,
    input [131:0]       walloc_in [32:0],
    output reg[131:0]   result_out,
    output reg          out_valid

);
///////////////first////////////////
wire [131:0] first_s       [10:0];
wire [131:0] first_cout    [10:0];
reg  [131:0] first_s_r     [10:0];
reg  [131:0] first_cout_r  [10:0];
reg          first_valid;
reg          secnod_valid;
reg          thrid_valid;
reg          fourth_valid;
reg          fifth_valid;
reg          sixth_valid;
reg          seven_valid;
always @(posedge clk ) begin
    if (rst) begin
        first_valid     <= 1'b0;
        secnod_valid    <= 1'b0;
        thrid_valid     <= 1'b0;
        fourth_valid    <= 1'b0;
        fifth_valid     <= 1'b0;
        sixth_valid     <= 1'b0;
        seven_valid     <= 1'b0;
        out_valid       <= 1'b0;
    end
    else begin
        first_valid     <= valid;
        secnod_valid    <= first_valid;
        thrid_valid     <= secnod_valid;
        fourth_valid    <= thrid_valid;
        fifth_valid     <= fourth_valid;
        sixth_valid     <= fifth_valid;
        seven_valid     <= sixth_valid;
        out_valid       <= seven_valid;
    end
end
genvar i;
generate
for(i=0; i<11; i++)begin
    ysyx_050369_csa_n csa_1_(.a(walloc_in[3*i+0]),.b(walloc_in[3*i+1]),.cin(walloc_in[3*i+2]),.cout(first_cout[i]),.s(first_s[i]));
    // assign first_cout_r[i] = {first_cout[i][130:0],1'b0};
end
endgenerate
generate
    for (i=0; i<11; i++) begin
        always @(posedge clk ) begin
            if (rst) begin 
                first_cout_r[i] <= 132'b0;
                first_s_r[i]    <= 132'b0;
            end
            else begin
                first_cout_r[i] <= {first_cout[i][130:0],1'b0};
                first_s_r[i]    <= first_s[i];
            end
        end
    end  
endgenerate
///////////////secnod//////////////
    wire [131:0] secnod_s   [6:0];
    wire [131:0] secnod_cout[6:0];
    reg  [131:0] secnod_cout_r [6:0];
    reg  [131:0] secnod_s_r [6:0];
    ysyx_050369_csa_n csa_2_01(.a(first_s_r[0])   ,.b(first_s_r[1])   ,.cin(first_s_r[2])   ,.cout(secnod_cout[0]),.s(secnod_s[0]));
    ysyx_050369_csa_n csa_2_02(.a(first_s_r[3])   ,.b(first_s_r[4])   ,.cin(first_s_r[5])   ,.cout(secnod_cout[1]),.s(secnod_s[1]));
    ysyx_050369_csa_n csa_2_03(.a(first_s_r[6])   ,.b(first_s_r[7])   ,.cin(first_s_r[8])   ,.cout(secnod_cout[2]),.s(secnod_s[2]));
    ysyx_050369_csa_n csa_2_04(.a(first_s_r[9])   ,.b(first_s_r[10])  ,.cin(first_cout_r[0]),.cout(secnod_cout[3]),.s(secnod_s[3]));
    ysyx_050369_csa_n csa_2_05(.a(first_cout_r[1]),.b(first_cout_r[2]),.cin(first_cout_r[3]),.cout(secnod_cout[4]),.s(secnod_s[4]));
    ysyx_050369_csa_n csa_2_06(.a(first_cout_r[4]),.b(first_cout_r[5]),.cin(first_cout_r[6]),.cout(secnod_cout[5]),.s(secnod_s[5]));
    ysyx_050369_csa_n csa_2_07(.a(first_cout_r[7]),.b(first_cout_r[8]),.cin(first_cout_r[9]),.cout(secnod_cout[6]),.s(secnod_s[6]));
generate
    for (i=0; i<7; i++) begin
        always @(posedge clk ) begin
            if (rst) begin 
                secnod_cout_r[i] <= 132'b0;
                secnod_s_r[i]    <= 132'b0;
            end
            else begin
                secnod_cout_r[i] <= {secnod_cout[i][130:0],1'b0};
                secnod_s_r[i]    <= secnod_s[i];
            end
        end
    end  
endgenerate
//////////////thrid////////////////
    wire [131:0] thrid_s   [4:0];
    wire [131:0] thrid_cout[4:0];
    reg  [131:0] thrid_cout_r [4:0];
    reg  [131:0] thrid_s_r [4:0];
    ysyx_050369_csa_n csa_3_01(.a(secnod_s_r[0])    ,.b(secnod_s_r[1])    ,.cin(secnod_s_r[2])    ,.cout(thrid_cout[0]),.s(thrid_s[0]));
    ysyx_050369_csa_n csa_3_02(.a(secnod_s_r[3])    ,.b(secnod_s_r[4])    ,.cin(secnod_s_r[5])    ,.cout(thrid_cout[1]),.s(thrid_s[1]));
    ysyx_050369_csa_n csa_3_03(.a(secnod_s_r[6])    ,.b(first_cout_r [10]),.cin(secnod_cout_r[ 0]),.cout(thrid_cout[2]),.s(thrid_s[2]));
    ysyx_050369_csa_n csa_3_04(.a(secnod_cout_r[ 1]),.b(secnod_cout_r[ 2]),.cin(secnod_cout_r[ 3]),.cout(thrid_cout[3]),.s(thrid_s[3]));
    ysyx_050369_csa_n csa_3_05(.a(secnod_cout_r[ 4]),.b(secnod_cout_r[ 5]),.cin(secnod_cout_r[ 6]),.cout(thrid_cout[4]),.s(thrid_s[4]));
generate
    for (i=0; i<5; i++) begin
        always @(posedge clk ) begin
            if (rst) begin 
                thrid_cout_r[i] <= 132'b0;
                thrid_s_r[i]    <= 132'b0;
            end
            else begin
                thrid_cout_r[i] <= {thrid_cout[i][130:0],1'b0};
                thrid_s_r[i]    <= thrid_s[i];
            end
        end
    end  
endgenerate
//////////////fourth////////////////
    wire [131:0] fourth_s   [2:0];
    wire [131:0] fourth_cout[2:0];
    reg  [131:0] fourth_s_r [2:0];
    reg  [131:0] fourth_cout_r [2:0];
    ysyx_050369_csa_n csa_4_01(.a(thrid_s_r[0])    ,.b(thrid_s_r[1])    ,.cin(thrid_s_r[2])   ,.cout(fourth_cout[0]),.s(fourth_s[0]));
    ysyx_050369_csa_n csa_4_02(.a(thrid_s_r[3])    ,.b(thrid_s_r[4])    ,.cin(thrid_cout_r[0]),.cout(fourth_cout[1]),.s(fourth_s[1]));
    ysyx_050369_csa_n csa_4_03(.a(thrid_cout_r[ 1]),.b(thrid_cout_r[ 2]),.cin(thrid_cout_r[3]),.cout(fourth_cout[2]),.s(fourth_s[2]));

always @(posedge clk ) begin
    if (rst) begin
        fourth_cout_r[0] <= 132'b0;
        fourth_cout_r[1] <= 132'b0;
        fourth_cout_r[2] <= 132'b0;
        fourth_s_r[0]    <= 132'b0;
        fourth_s_r[1]    <= 132'b0;
        fourth_s_r[2]    <= 132'b0;
    end
    else begin
        fourth_s_r[0]    <= fourth_s[0];
        fourth_s_r[1]    <= fourth_s[1];
        fourth_s_r[2]    <= fourth_s[2];
        fourth_cout_r[0] <= {fourth_cout[0][130:0],1'b0};
        fourth_cout_r[1] <= {fourth_cout[1][130:0],1'b0};
        fourth_cout_r[2] <= {fourth_cout[2][130:0],1'b0};
    end
end
//////////////fifth/////////////////
    wire [131:0] fifth_s   [1:0];
    wire [131:0] fifth_cout[1:0];
    reg  [131:0] fifth_s_r [1:0];
    reg  [131:0] fifth_cout_r [1:0];
    ysyx_050369_csa_n csa_5_01(.a(fourth_s_r[0])  ,.b(fourth_s_r[1])   ,.cin(fourth_s_r[2])   ,.cout(fifth_cout[0]),.s(fifth_s[0]));
    ysyx_050369_csa_n csa_5_02(.a(thrid_cout_r[4]),.b(fourth_cout_r[0]),.cin(fourth_cout_r[1]),.cout(fifth_cout[1]),.s(fifth_s[1]));
always @(posedge clk ) begin
    if (rst) begin
        fifth_s_r[0]    <= 132'b0;
        fifth_s_r[1]    <= 132'b0;
        fifth_cout_r[0] <= 132'b0;
        fifth_cout_r[1] <= 132'b0;
    end
    else begin
        fifth_s_r[0]    <= fifth_s[0];
        fifth_s_r[1]    <= fifth_s[1];
        fifth_cout_r[0] <= {fifth_cout[0][130:0],1'b0};
        fifth_cout_r[1] <= {fifth_cout[1][130:0],1'b0};
    end
end
///////////////sixth////////////// /
    wire [131:0]sixth_s;
    wire [131:0]sixth_cout;
    reg  [131:0]sixth_s_r;
    reg  [131:0]sixth_cout_r;
    ysyx_050369_csa_n csa_6_01(.a(fifth_s_r[0]),.b(fifth_s_r[1]),.cin(fourth_cout_r[2]) ,.cout(sixth_cout   ),.s(sixth_s   ));
always @(posedge clk ) begin
    if (rst) begin
        sixth_s_r    <= 132'b0;
        sixth_cout_r <= 132'b0;
    end
    else begin
        sixth_s_r    <= sixth_s;
        sixth_cout_r <= {sixth_cout[130:0],1'b0};
    end
end
///////////////seven///////////////
    wire [131:0]seven_s;
    wire [131:0]seven_cout;
    reg  [131:0]seven_s_r;
    reg  [131:0]seven_cout_r;
    ysyx_050369_csa_n csa_7_01(.a(sixth_s_r ),.b(fifth_cout_r[0]),.cin(fifth_cout_r[1]) ,.cout(seven_cout   ),.s(seven_s   ));
always @(posedge clk ) begin
    if (rst) begin
        seven_s_r    <= 132'b0;
        seven_cout_r <= 132'b0;
    end
    else begin
        seven_s_r    <= seven_s;
        seven_cout_r <= {seven_cout[130:0],1'b0};
    end
end
///////////////eight///////////////
    wire [131:0]eight_s;
    wire [131:0]eight_cout;
    ysyx_050369_csa_n csa_8_01(.a(seven_s_r   ),.b(seven_cout_r)    ,.cin(sixth_cout_r)     ,.cout(eight_cout   ),.s(eight_s ));
always @(posedge clk ) begin
    if (rst) begin
        result_out <= 132'b0;
    end
    else begin
        result_out <=eight_s+{eight_cout[130:0],1'b0};
    end
end
endmodule

module ysyx_050369_csa_n#(
  len = 132
)(
  input [len-1:0] a,
  input [len-1:0] b,
  input [len-1:0] cin,
  output[len-1:0] cout,
  output[len-1:0] s

);
genvar i;
generate
  for(i=0; i<len; i++)begin
      assign s[i]    = a[i] ^ b[i] ^ cin[i];
      assign cout[i] = a[i] & b[i] | b[i] & cin[i] | a[i] & cin[i];  
  end
endgenerate
endmodule
module ysyx_050369_Bmultiplier  (
    input               clk,
    input               rst,
    input               mul_valid,
    input               flush,//	为高表示取消乘法
    input               mulw,//为高表示是 32 位乘法
    input   [1:0]       mul_signed,//2’b11（signed x signed）；2’b10（signed x unsigned）；2’b00（unsigned x unsigned）；
    input   [63:0]      multiplicand,
    input   [63:0]      multiplier,
    output reg          mul_ready,
    output reg          out_valid,
    output reg [63:0]   result_hi,
    output reg [63:0]   result_lo
);

    wire [65:0] multiplier_temp;
    wire [65:0] multiplicand_temp;
    reg         walloc_ivalid;
    reg         walloc_ovalid;
    wire [131:0]res;
    parameter IDLE = 3'b0,START=3'b1,RUN=3'd2,OUT=3'd3;
    reg [2:0]state,next_state;
    always @(posedge clk ) begin
        if (rst||flush) begin
            state <= IDLE;
        end
        else begin
            state <= next_state;
        end
    end
    always @(*) begin
        if (flush) begin
            next_state = IDLE;
        end
        else begin
            case (state)
                IDLE:  next_state = mul_valid?START:IDLE;
                START: next_state = RUN;
                RUN:   next_state = walloc_ovalid?OUT:RUN;
                OUT:   next_state = IDLE;
                default: next_state = IDLE;
            endcase
        end
        
    end
    always @(posedge clk ) begin
        if (rst||flush) begin
            walloc_ivalid    <= 1'b0;
            mul_ready        <= 1'b0;
            out_valid        <= 1'b0;
            result_hi        <= 64'b0;
            result_lo        <= 64'b0;
        end
        else begin
            case (next_state)
                IDLE:  begin
                    walloc_ivalid    <= 1'b0;
                    mul_ready        <= 1'b1;
                    out_valid        <= 1'b0;
                end
                START: begin
                    walloc_ivalid    <= 1'b1;
                    mul_ready        <= 1'b0;
                    out_valid        <= 1'b0;
                end
                RUN:   begin
                    walloc_ivalid    <= 1'b0; 
                    mul_ready        <= 1'b0;
                    out_valid        <= 1'b0;
                end
                OUT:   begin
                    // result_lo <= mulw?{{32{res[31]}},res[31:0]}:res[63:0];
                    result_hi        <= res[127:64];
                    result_lo        <= mulw?{{32{res[31]}},res[31:0]}:res[63:0];
                    mul_ready        <= 1'b0;
                    out_valid        <= 1'b1;
                end
                default: begin
                    walloc_ivalid    <= 1'b0;
                    mul_ready        <= 1'b0;
                    out_valid        <= 1'b0;
                    result_hi        <= 64'b0;
                    result_lo        <= 64'b0;
                end
            endcase
        end
    end
    assign multiplicand_temp = mul_signed[1]?(mulw?{{34{multiplicand[31]}},multiplicand[31:0]}:{{2{multiplicand[63]}},multiplicand[63:0]})
                                            :(mulw?{{34{1'b0}},multiplicand[31:0]}            :{{2{1'b0}},multiplicand[63:0]});

    assign multiplier_temp   = mul_signed[0]?(mulw?{{34{multiplier[31]}},multiplier[31:0]}:{{2{multiplier[63]}},multiplier[63:0]})
                                            :(mulw?{{34{1'b0}},multiplier[31:0]}          :{{2{1'b0}},multiplier[63:0]});
    wire [66:0] p_temp [32:0];
    wire [131:0]walloc_in[32:0];
    wire [32:0] c_temp;
        ysyx_050369_Par_product Par_0(.src({multiplicand_temp[1:0],1'b0}) ,.X(multiplier_temp),.C(c_temp[0]),.P(p_temp[0]));
	genvar i;
	generate
  	for(i=1; i<33; i++)begin
        ysyx_050369_Par_product Par_ (.src(multiplicand_temp[2*i+1:2*i-1]),.X(multiplier_temp),.C(c_temp[i]),.P(p_temp[i]));
    end
    // ysyx_050369_Par_product Par_32 (.src(multiplicand_temp[65:63]),.X(multiplier_temp),.C(),.P(p_temp[32]));
    endgenerate
    assign walloc_in[0] = {{65{p_temp[0][65]}},p_temp[0]};
    generate
  	for(i=1; i<33; i++)begin
        assign walloc_in[i] = {{{(65-2*i){p_temp[i][65]}}},p_temp[i] ,1'b0, c_temp[i-1], {(2*i-2){1'b0}}};
    end
    endgenerate
    ysyx_050369_walloc_n walloc_n(
        .clk        (clk),
        .rst        (rst),
        .valid      (walloc_ivalid),
        .walloc_in  (walloc_in),
        .result_out (res),
        .out_valid  (walloc_ovalid)
    );

endmodule